home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / gnu / shllutil.lha / shellutils-1.8 / lib / getdate.y < prev    next >
Text File  |  1992-09-30  |  23KB  |  966 lines

  1. %{
  2. /* $Revision: 2.1 $
  3. **
  4. **  Originally written by Steven M. Bellovin <smb@research.att.com> while
  5. **  at the University of North Carolina at Chapel Hill.  Later tweaked by
  6. **  a couple of people on Usenet.  Completely overhauled by Rich $alz
  7. **  <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990;
  8. **  send any email to Rich.
  9. **
  10. **  This grammar has eight shift/reduce conflicts.
  11. **
  12. **  This code is in the public domain and has no copyright.
  13. */
  14. /* SUPPRESS 287 on yaccpar_sccsid *//* Unusd static variable */
  15. /* SUPPRESS 288 on yyerrlab *//* Label unused */
  16.  
  17. #ifdef __GNUC__
  18. #define alloca __builtin_alloca
  19. #else
  20. #ifdef sparc
  21. #include <alloca.h>
  22. #else
  23. #ifdef _AIX /* for Bison */
  24.  #pragma alloca
  25. #else
  26. char *alloca ();
  27. #endif
  28. #endif
  29. #endif
  30.  
  31. #include <stdio.h>
  32. #include <ctype.h>
  33.  
  34. /* The code at the top of get_date which figures out the offset of the
  35.    current time zone checks various CPP symbols to see if special
  36.    tricks are need, but defaults to using the gettimeofday system call.
  37.    Include <sys/time.h> if that will be used.  */
  38.  
  39. #if !defined (USG) && !defined (sgi) && !defined (__386BSD__)
  40. #include <sys/time.h>
  41. #endif
  42.  
  43. #if    defined(vms)
  44.  
  45. #include <types.h>
  46. #include <time.h>
  47.  
  48. #else
  49.  
  50. #include <sys/types.h>
  51.  
  52. #if    defined(USG) || !defined(HAVE_FTIME)
  53. /*
  54. **  If you need to do a tzset() call to set the
  55. **  timezone, and don't have ftime().
  56. */
  57. struct timeb {
  58.     time_t        time;        /* Seconds since the epoch    */
  59.     unsigned short    millitm;    /* Field not used        */
  60.     short        timezone;
  61.     short        dstflag;    /* Field not used        */
  62. };
  63.  
  64. #else
  65.  
  66. #include <sys/timeb.h>
  67.  
  68. #endif    /* defined(USG) && !defined(HAVE_FTIME) */
  69.  
  70. #if    defined(BSD4_2) || defined(BSD4_1C) || (defined (hp9000) && !defined (hpux))
  71. #include <sys/time.h>
  72. #else
  73. #if defined(_AIX)
  74. #include <sys/time.h>
  75. #endif
  76. #include <time.h>
  77. #endif    /* defined(BSD4_2) */
  78.  
  79. #endif    /* defined(vms) */
  80.  
  81. #if defined (STDC_HEADERS) || defined (USG)
  82. #include <string.h>
  83. #endif
  84.  
  85. #if sgi
  86. #undef timezone
  87. #endif
  88.  
  89. extern struct tm    *localtime();
  90.  
  91. #define yyparse getdate_yyparse
  92. #define yylex getdate_yylex
  93. #define yyerror getdate_yyerror
  94.  
  95. #if    !defined(lint) && !defined(SABER)
  96. static char RCS[] =
  97.     "$Header: str2date.y,v 2.1 90/09/06 08:15:06 cronan Exp $";
  98. #endif    /* !defined(lint) && !defined(SABER) */
  99.  
  100.  
  101. #define EPOCH        1970
  102. #define HOUR(x)        ((time_t)(x) * 60)
  103. #define SECSPERDAY    (24L * 60L * 60L)
  104.  
  105.  
  106. /*
  107. **  An entry in the lexical lookup table.
  108. */
  109. typedef struct _TABLE {
  110.     char    *name;
  111.     int        type;
  112.     time_t    value;
  113. } TABLE;
  114.  
  115.  
  116. /*
  117. **  Daylight-savings mode:  on, off, or not yet known.
  118. */
  119. typedef enum _DSTMODE {
  120.     DSTon, DSToff, DSTmaybe
  121. } DSTMODE;
  122.  
  123. /*
  124. **  Meridian:  am, pm, or 24-hour style.
  125. */
  126. typedef enum _MERIDIAN {
  127.     MERam, MERpm, MER24
  128. } MERIDIAN;
  129.  
  130.  
  131. /*
  132. **  Global variables.  We could get rid of most of these by using a good
  133. **  union as the yacc stack.  (This routine was originally written before
  134. **  yacc had the %union construct.)  Maybe someday; right now we only use
  135. **  the %union very rarely.
  136. */
  137. static char    *yyInput;
  138. static DSTMODE    yyDSTmode;
  139. static time_t    yyDayOrdinal;
  140. static time_t    yyDayNumber;
  141. static int    yyHaveDate;
  142. static int    yyHaveDay;
  143. static int    yyHaveRel;
  144. static int    yyHaveTime;
  145. static int    yyHaveZone;
  146. static time_t    yyTimezone;
  147. static time_t    yyDay;
  148. static time_t    yyHour;
  149. static time_t    yyMinutes;
  150. static time_t    yyMonth;
  151. static time_t    yySeconds;
  152. static time_t    yyYear;
  153. static MERIDIAN    yyMeridian;
  154. static time_t    yyRelMonth;
  155. static time_t    yyRelSeconds;
  156.  
  157. %}
  158.  
  159. %union {
  160.     time_t        Number;
  161.     enum _MERIDIAN    Meridian;
  162. }
  163.  
  164. %token    tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
  165. %token    tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST
  166.  
  167. %type    <Number>    tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT
  168. %type    <Number>    tSEC_UNIT tSNUMBER tUNUMBER tZONE
  169. %type    <Meridian>    tMERIDIAN o_merid
  170.  
  171. %%
  172.  
  173. spec    : /* NULL */
  174.     | spec item
  175.     ;
  176.  
  177. item    : time {
  178.         yyHaveTime++;
  179.     }
  180.     | zone {
  181.         yyHaveZone++;
  182.     }
  183.     | date {
  184.         yyHaveDate++;
  185.     }
  186.     | day {
  187.         yyHaveDay++;
  188.     }
  189.     | rel {
  190.         yyHaveRel++;
  191.     }
  192.     | number
  193.     ;
  194.  
  195. time    : tUNUMBER tMERIDIAN {
  196.         yyHour = $1;
  197.         yyMinutes = 0;
  198.         yySeconds = 0;
  199.         yyMeridian = $2;
  200.     }
  201.     | tUNUMBER ':' tUNUMBER o_merid {
  202.         yyHour = $1;
  203.         yyMinutes = $3;
  204.         yySeconds = 0;
  205.         yyMeridian = $4;
  206.     }
  207.     | tUNUMBER ':' tUNUMBER tSNUMBER {
  208.         yyHour = $1;
  209.         yyMinutes = $3;
  210.         yyMeridian = MER24;
  211.         yyDSTmode = DSToff;
  212.         yyTimezone = - ($4 % 100 + ($4 / 100) * 60);
  213.     }
  214.     | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
  215.         yyHour = $1;
  216.         yyMinutes = $3;
  217.         yySeconds = $5;
  218.         yyMeridian = $6;
  219.     }
  220.     | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER {
  221.         yyHour = $1;
  222.         yyMinutes = $3;
  223.         yySeconds = $5;
  224.         yyMeridian = MER24;
  225.         yyDSTmode = DSToff;
  226.         yyTimezone = - ($6 % 100 + ($6 / 100) * 60);
  227.     }
  228.     ;
  229.  
  230. zone    : tZONE {
  231.         yyTimezone = $1;
  232.         yyDSTmode = DSToff;
  233.     }
  234.     | tDAYZONE {
  235.         yyTimezone = $1;
  236.         yyDSTmode = DSTon;
  237.     }
  238.     |
  239.       tZONE tDST {
  240.         yyTimezone = $1;
  241.         yyDSTmode = DSTon;
  242.     }
  243.     ;
  244.  
  245. day    : tDAY {
  246.         yyDayOrdinal = 1;
  247.         yyDayNumber = $1;
  248.     }
  249.     | tDAY ',' {
  250.         yyDayOrdinal = 1;
  251.         yyDayNumber = $1;
  252.     }
  253.     | tUNUMBER tDAY {
  254.         yyDayOrdinal = $1;
  255.         yyDayNumber = $2;
  256.     }
  257.     ;
  258.  
  259. date    : tUNUMBER '/' tUNUMBER {
  260.         yyMonth = $1;
  261.         yyDay = $3;
  262.     }
  263.     | tUNUMBER '/' tUNUMBER '/' tUNUMBER {
  264.         yyMonth = $1;
  265.         yyDay = $3;
  266.         yyYear = $5;
  267.     }
  268.     | tUNUMBER tSNUMBER tSNUMBER {
  269.         /* ISO 8601 format.  yyyy-mm-dd.  */
  270.         yyYear = $1;
  271.         yyMonth = -$2;
  272.         yyDay = -$3;
  273.     }
  274.     | tMONTH tUNUMBER {
  275.         yyMonth = $1;
  276.         yyDay = $2;
  277.     }
  278.     | tMONTH tUNUMBER ',' tUNUMBER {
  279.         yyMonth = $1;
  280.         yyDay = $2;
  281.         yyYear = $4;
  282.     }
  283.     | tUNUMBER tMONTH {
  284.         yyMonth = $2;
  285.         yyDay = $1;
  286.     }
  287.     | tUNUMBER tMONTH tUNUMBER {
  288.         yyMonth = $2;
  289.         yyDay = $1;
  290.         yyYear = $3;
  291.     }
  292.     ;
  293.  
  294. rel    : relunit tAGO {
  295.         yyRelSeconds = -yyRelSeconds;
  296.         yyRelMonth = -yyRelMonth;
  297.     }
  298.     | relunit
  299.     ;
  300.  
  301. relunit    : tUNUMBER tMINUTE_UNIT {
  302.         yyRelSeconds += $1 * $2 * 60L;
  303.     }
  304.     | tSNUMBER tMINUTE_UNIT {
  305.         yyRelSeconds += $1 * $2 * 60L;
  306.     }
  307.     | tMINUTE_UNIT {
  308.         yyRelSeconds += $1 * 60L;
  309.     }
  310.     | tSNUMBER tSEC_UNIT {
  311.         yyRelSeconds += $1;
  312.     }
  313.     | tUNUMBER tSEC_UNIT {
  314.         yyRelSeconds += $1;
  315.     }
  316.     | tSEC_UNIT {
  317.         yyRelSeconds++;
  318.     }
  319.     | tSNUMBER tMONTH_UNIT {
  320.         yyRelMonth += $1 * $2;
  321.     }
  322.     | tUNUMBER tMONTH_UNIT {
  323.         yyRelMonth += $1 * $2;
  324.     }
  325.     | tMONTH_UNIT {
  326.         yyRelMonth += $1;
  327.     }
  328.     ;
  329.  
  330. number    : tUNUMBER {
  331.         if (yyHaveTime && yyHaveDate && !yyHaveRel)
  332.         yyYear = $1;
  333.         else {
  334.         if($1>10000) {
  335.             time_t date_part;
  336.  
  337.             date_part= $1/10000;
  338.             yyHaveDate++;
  339.             yyDay= (date_part)%100;
  340.             yyMonth= (date_part/100)%100;
  341.             yyYear = date_part/10000;
  342.         } 
  343.             yyHaveTime++;
  344.         if ($1 < 100) {
  345.             yyHour = $1;
  346.             yyMinutes = 0;
  347.         }
  348.         else {
  349.             yyHour = $1 / 100;
  350.             yyMinutes = $1 % 100;
  351.         }
  352.         yySeconds = 0;
  353.         yyMeridian = MER24;
  354.         }
  355.     }
  356.     ;
  357.  
  358. o_merid    : /* NULL */ {
  359.         $$ = MER24;
  360.     }
  361.     | tMERIDIAN {
  362.         $$ = $1;
  363.     }
  364.     ;
  365.  
  366. %%
  367.  
  368. /* Month and day table. */
  369. static TABLE    MonthDayTable[] = {
  370.     { "january",    tMONTH,  1 },
  371.     { "february",    tMONTH,  2 },
  372.     { "march",        tMONTH,  3 },
  373.     { "april",        tMONTH,  4 },
  374.     { "may",        tMONTH,  5 },
  375.     { "june",        tMONTH,  6 },
  376.     { "july",        tMONTH,  7 },
  377.     { "august",        tMONTH,  8 },
  378.     { "september",    tMONTH,  9 },
  379.     { "sept",        tMONTH,  9 },
  380.     { "october",    tMONTH, 10 },
  381.     { "november",    tMONTH, 11 },
  382.     { "december",    tMONTH, 12 },
  383.     { "sunday",        tDAY, 0 },
  384.     { "monday",        tDAY, 1 },
  385.     { "tuesday",    tDAY, 2 },
  386.     { "tues",        tDAY, 2 },
  387.     { "wednesday",    tDAY, 3 },
  388.     { "wednes",        tDAY, 3 },
  389.     { "thursday",    tDAY, 4 },
  390.     { "thur",        tDAY, 4 },
  391.     { "thurs",        tDAY, 4 },
  392.     { "friday",        tDAY, 5 },
  393.     { "saturday",    tDAY, 6 },
  394.     { NULL }
  395. };
  396.  
  397. /* Time units table. */
  398. static TABLE    UnitsTable[] = {
  399.     { "year",        tMONTH_UNIT,    12 },
  400.     { "month",        tMONTH_UNIT,    1 },
  401.     { "fortnight",    tMINUTE_UNIT,    14 * 24 * 60 },
  402.     { "week",        tMINUTE_UNIT,    7 * 24 * 60 },
  403.     { "day",        tMINUTE_UNIT,    1 * 24 * 60 },
  404.     { "hour",        tMINUTE_UNIT,    60 },
  405.     { "minute",        tMINUTE_UNIT,    1 },
  406.     { "min",        tMINUTE_UNIT,    1 },
  407.     { "second",        tSEC_UNIT,    1 },
  408.     { "sec",        tSEC_UNIT,    1 },
  409.     { NULL }
  410. };
  411.  
  412. /* Assorted relative-time words. */
  413. static TABLE    OtherTable[] = {
  414.     { "tomorrow",    tMINUTE_UNIT,    1 * 24 * 60 },
  415.     { "yesterday",    tMINUTE_UNIT,    -1 * 24 * 60 },
  416.     { "today",        tMINUTE_UNIT,    0 },
  417.     { "now",        tMINUTE_UNIT,    0 },
  418.     { "last",        tUNUMBER,    -1 },
  419.     { "this",        tMINUTE_UNIT,    0 },
  420.     { "next",        tUNUMBER,    2 },
  421.     { "first",        tUNUMBER,    1 },
  422. /*  { "second",        tUNUMBER,    2 }, */
  423.     { "third",        tUNUMBER,    3 },
  424.     { "fourth",        tUNUMBER,    4 },
  425.     { "fifth",        tUNUMBER,    5 },
  426.     { "sixth",        tUNUMBER,    6 },
  427.     { "seventh",    tUNUMBER,    7 },
  428.     { "eighth",        tUNUMBER,    8 },
  429.     { "ninth",        tUNUMBER,    9 },
  430.     { "tenth",        tUNUMBER,    10 },
  431.     { "eleventh",    tUNUMBER,    11 },
  432.     { "twelfth",    tUNUMBER,    12 },
  433.     { "ago",        tAGO,    1 },
  434.     { NULL }
  435. };
  436.  
  437. /* The timezone table. */
  438. /* Some of these are commented out because a time_t can't store a float. */
  439. static TABLE    TimezoneTable[] = {
  440.     { "gmt",    tZONE,     HOUR( 0) },    /* Greenwich Mean */
  441.     { "ut",    tZONE,     HOUR( 0) },    /* Universal (Coordinated) */
  442.     { "utc",    tZONE,     HOUR( 0) },
  443.     { "wet",    tZONE,     HOUR( 0) },    /* Western European */
  444.     { "bst",    tDAYZONE,  HOUR( 0) },    /* British Summer */
  445.     { "wat",    tZONE,     HOUR( 1) },    /* West Africa */
  446.     { "at",    tZONE,     HOUR( 2) },    /* Azores */
  447. #if    0
  448.     /* For completeness.  BST is also British Summer, and GST is
  449.      * also Guam Standard. */
  450.     { "bst",    tZONE,     HOUR( 3) },    /* Brazil Standard */
  451.     { "gst",    tZONE,     HOUR( 3) },    /* Greenland Standard */
  452. #endif
  453. #if 0
  454.     { "nft",    tZONE,     HOUR(3.5) },    /* Newfoundland */
  455.     { "nst",    tZONE,     HOUR(3.5) },    /* Newfoundland Standard */
  456.     { "ndt",    tDAYZONE,  HOUR(3.5) },    /* Newfoundland Daylight */
  457. #endif
  458.     { "ast",    tZONE,     HOUR( 4) },    /* Atlantic Standard */
  459.     { "adt",    tDAYZONE,  HOUR( 4) },    /* Atlantic Daylight */
  460.     { "est",    tZONE,     HOUR( 5) },    /* Eastern Standard */
  461.     { "edt",    tDAYZONE,  HOUR( 5) },    /* Eastern Daylight */
  462.     { "cst",    tZONE,     HOUR( 6) },    /* Central Standard */
  463.     { "cdt",    tDAYZONE,  HOUR( 6) },    /* Central Daylight */
  464.     { "mst",    tZONE,     HOUR( 7) },    /* Mountain Standard */
  465.     { "mdt",    tDAYZONE,  HOUR( 7) },    /* Mountain Daylight */
  466.     { "pst",    tZONE,     HOUR( 8) },    /* Pacific Standard */
  467.     { "pdt",    tDAYZONE,  HOUR( 8) },    /* Pacific Daylight */
  468.     { "yst",    tZONE,     HOUR( 9) },    /* Yukon Standard */
  469.     { "ydt",    tDAYZONE,  HOUR( 9) },    /* Yukon Daylight */
  470.     { "hst",    tZONE,     HOUR(10) },    /* Hawaii Standard */
  471.     { "hdt",    tDAYZONE,  HOUR(10) },    /* Hawaii Daylight */
  472.     { "cat",    tZONE,     HOUR(10) },    /* Central Alaska */
  473.     { "ahst",    tZONE,     HOUR(10) },    /* Alaska-Hawaii Standard */
  474.     { "nt",    tZONE,     HOUR(11) },    /* Nome */
  475.     { "idlw",    tZONE,     HOUR(12) },    /* International Date Line West */
  476.     { "cet",    tZONE,     -HOUR(1) },    /* Central European */
  477.     { "met",    tZONE,     -HOUR(1) },    /* Middle European */
  478.     { "mewt",    tZONE,     -HOUR(1) },    /* Middle European Winter */
  479.     { "mest",    tDAYZONE,  -HOUR(1) },    /* Middle European Summer */
  480.     { "swt",    tZONE,     -HOUR(1) },    /* Swedish Winter */
  481.     { "sst",    tDAYZONE,  -HOUR(1) },    /* Swedish Summer */
  482.     { "fwt",    tZONE,     -HOUR(1) },    /* French Winter */
  483.     { "fst",    tDAYZONE,  -HOUR(1) },    /* French Summer */
  484.     { "eet",    tZONE,     -HOUR(2) },    /* Eastern Europe, USSR Zone 1 */
  485.     { "bt",    tZONE,     -HOUR(3) },    /* Baghdad, USSR Zone 2 */
  486. #if 0
  487.     { "it",    tZONE,     -HOUR(3.5) },/* Iran */
  488. #endif
  489.     { "zp4",    tZONE,     -HOUR(4) },    /* USSR Zone 3 */
  490.     { "zp5",    tZONE,     -HOUR(5) },    /* USSR Zone 4 */
  491. #if 0
  492.     { "ist",    tZONE,     -HOUR(5.5) },/* Indian Standard */
  493. #endif
  494.     { "zp6",    tZONE,     -HOUR(6) },    /* USSR Zone 5 */
  495. #if    0
  496.     /* For completeness.  NST is also Newfoundland Stanard, and SST is
  497.      * also Swedish Summer. */
  498.     { "nst",    tZONE,     -HOUR(6.5) },/* North Sumatra */
  499.     { "sst",    tZONE,     -HOUR(7) },    /* South Sumatra, USSR Zone 6 */
  500. #endif    /* 0 */
  501.     { "wast",    tZONE,     -HOUR(7) },    /* West Australian Standard */
  502.     { "wadt",    tDAYZONE,  -HOUR(7) },    /* West Australian Daylight */
  503. #if 0
  504.     { "jt",    tZONE,     -HOUR(7.5) },/* Java (3pm in Cronusland!) */
  505. #endif
  506.     { "cct",    tZONE,     -HOUR(8) },    /* China Coast, USSR Zone 7 */
  507.     { "jst",    tZONE,     -HOUR(9) },    /* Japan Standard, USSR Zone 8 */
  508. #if 0
  509.     { "cast",    tZONE,     -HOUR(9.5) },/* Central Australian Standard */
  510.     { "cadt",    tDAYZONE,  -HOUR(9.5) },/* Central Australian Daylight */
  511. #endif
  512.     { "east",    tZONE,     -HOUR(10) },    /* Eastern Australian Standard */
  513.     { "eadt",    tDAYZONE,  -HOUR(10) },    /* Eastern Australian Daylight */
  514.     { "gst",    tZONE,     -HOUR(10) },    /* Guam Standard, USSR Zone 9 */
  515.     { "nzt",    tZONE,     -HOUR(12) },    /* New Zealand */
  516.     { "nzst",    tZONE,     -HOUR(12) },    /* New Zealand Standard */
  517.     { "nzdt",    tDAYZONE,  -HOUR(12) },    /* New Zealand Daylight */
  518.     { "idle",    tZONE,     -HOUR(12) },    /* International Date Line East */
  519.     {  NULL  }
  520. };
  521.  
  522. /* Military timezone table. */
  523. static TABLE    MilitaryTable[] = {
  524.     { "a",    tZONE,    HOUR(  1) },
  525.     { "b",    tZONE,    HOUR(  2) },
  526.     { "c",    tZONE,    HOUR(  3) },
  527.     { "d",    tZONE,    HOUR(  4) },
  528.     { "e",    tZONE,    HOUR(  5) },
  529.     { "f",    tZONE,    HOUR(  6) },
  530.     { "g",    tZONE,    HOUR(  7) },
  531.     { "h",    tZONE,    HOUR(  8) },
  532.     { "i",    tZONE,    HOUR(  9) },
  533.     { "k",    tZONE,    HOUR( 10) },
  534.     { "l",    tZONE,    HOUR( 11) },
  535.     { "m",    tZONE,    HOUR( 12) },
  536.     { "n",    tZONE,    HOUR(- 1) },
  537.     { "o",    tZONE,    HOUR(- 2) },
  538.     { "p",    tZONE,    HOUR(- 3) },
  539.     { "q",    tZONE,    HOUR(- 4) },
  540.     { "r",    tZONE,    HOUR(- 5) },
  541.     { "s",    tZONE,    HOUR(- 6) },
  542.     { "t",    tZONE,    HOUR(- 7) },
  543.     { "u",    tZONE,    HOUR(- 8) },
  544.     { "v",    tZONE,    HOUR(- 9) },
  545.     { "w",    tZONE,    HOUR(-10) },
  546.     { "x",    tZONE,    HOUR(-11) },
  547.     { "y",    tZONE,    HOUR(-12) },
  548.     { "z",    tZONE,    HOUR(  0) },
  549.     { NULL }
  550. };
  551.  
  552.  
  553.  
  554.  
  555. /* ARGSUSED */
  556. int
  557. yyerror(s)
  558.     char    *s;
  559. {
  560.   return 0;
  561. }
  562.  
  563.  
  564. static time_t
  565. ToSeconds(Hours, Minutes, Seconds, Meridian)
  566.     time_t    Hours;
  567.     time_t    Minutes;
  568.     time_t    Seconds;
  569.     MERIDIAN    Meridian;
  570. {
  571.     if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
  572.     return -1;
  573.     switch (Meridian) {
  574.     case MER24:
  575.     if (Hours < 0 || Hours > 23)
  576.         return -1;
  577.     return (Hours * 60L + Minutes) * 60L + Seconds;
  578.     case MERam:
  579.     if (Hours < 1 || Hours > 12)
  580.         return -1;
  581.     return (Hours * 60L + Minutes) * 60L + Seconds;
  582.     case MERpm:
  583.     if (Hours < 1 || Hours > 12)
  584.         return -1;
  585.     return ((Hours + 12) * 60L + Minutes) * 60L + Seconds;
  586.     }
  587.     /* NOTREACHED */
  588. }
  589.  
  590.  
  591. static time_t
  592. Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode)
  593.     time_t    Month;
  594.     time_t    Day;
  595.     time_t    Year;
  596.     time_t    Hours;
  597.     time_t    Minutes;
  598.     time_t    Seconds;
  599.     MERIDIAN    Meridian;
  600.     DSTMODE    DSTmode;
  601. {
  602.     static int    DaysInMonth[12] = {
  603.     31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  604.     };
  605.     time_t    tod;
  606.     time_t    Julian;
  607.     int        i;
  608.  
  609.     if (Year < 0)
  610.     Year = -Year;
  611.     if (Year < 100)
  612.     Year += 1900;
  613.     DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
  614.             ? 29 : 28;
  615.     if (Year < EPOCH || Year > 1999
  616.      || Month < 1 || Month > 12
  617.      /* Lint fluff:  "conversion from long may lose accuracy" */
  618.      || Day < 1 || Day > DaysInMonth[(int)--Month])
  619.     return -1;
  620.  
  621.     for (Julian = Day - 1, i = 0; i < Month; i++)
  622.     Julian += DaysInMonth[i];
  623.     for (i = EPOCH; i < Year; i++)
  624.     Julian += 365 + (i % 4 == 0);
  625.     Julian *= SECSPERDAY;
  626.     Julian += yyTimezone * 60L;
  627.     if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
  628.     return -1;
  629.     Julian += tod;
  630.     if (DSTmode == DSTon
  631.      || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst))
  632.     Julian -= 60 * 60;
  633.     return Julian;
  634. }
  635.  
  636.  
  637. static time_t
  638. DSTcorrect(Start, Future)
  639.     time_t    Start;
  640.     time_t    Future;
  641. {
  642.     time_t    StartDay;
  643.     time_t    FutureDay;
  644.  
  645.     StartDay = (localtime(&Start)->tm_hour + 1) % 24;
  646.     FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
  647.     return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
  648. }
  649.  
  650.  
  651. static time_t
  652. RelativeDate(Start, DayOrdinal, DayNumber)
  653.     time_t    Start;
  654.     time_t    DayOrdinal;
  655.     time_t    DayNumber;
  656. {
  657.     struct tm    *tm;
  658.     time_t    now;
  659.  
  660.     now = Start;
  661.     tm = localtime(&now);
  662.     now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7);
  663.     now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
  664.     return DSTcorrect(Start, now);
  665. }
  666.  
  667.  
  668. static time_t
  669. RelativeMonth(Start, RelMonth)
  670.     time_t    Start;
  671.     time_t    RelMonth;
  672. {
  673.     struct tm    *tm;
  674.     time_t    Month;
  675.     time_t    Year;
  676.  
  677.     if (RelMonth == 0)
  678.     return 0;
  679.     tm = localtime(&Start);
  680.     Month = 12 * tm->tm_year + tm->tm_mon + RelMonth;
  681.     Year = Month / 12;
  682.     Month = Month % 12 + 1;
  683.     return DSTcorrect(Start,
  684.         Convert(Month, (time_t)tm->tm_mday, Year,
  685.         (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
  686.         MER24, DSTmaybe));
  687. }
  688.  
  689.  
  690. static int
  691. LookupWord(buff)
  692.     char        *buff;
  693. {
  694.     register char    *p;
  695.     register char    *q;
  696.     register TABLE    *tp;
  697.     int            i;
  698.     int            abbrev;
  699.  
  700.     /* Make it lowercase. */
  701.     for (p = buff; *p; p++)
  702.     if (isupper(*p))
  703.         *p = tolower(*p);
  704.  
  705.     if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) {
  706.     yylval.Meridian = MERam;
  707.     return tMERIDIAN;
  708.     }
  709.     if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) {
  710.     yylval.Meridian = MERpm;
  711.     return tMERIDIAN;
  712.     }
  713.  
  714.     /* See if we have an abbreviation for a month. */
  715.     if (strlen(buff) == 3)
  716.     abbrev = 1;
  717.     else if (strlen(buff) == 4 && buff[3] == '.') {
  718.     abbrev = 1;
  719.     buff[3] = '\0';
  720.     }
  721.     else
  722.     abbrev = 0;
  723.  
  724.     for (tp = MonthDayTable; tp->name; tp++) {
  725.     if (abbrev) {
  726.         if (strncmp(buff, tp->name, 3) == 0) {
  727.         yylval.Number = tp->value;
  728.         return tp->type;
  729.         }
  730.     }
  731.     else if (strcmp(buff, tp->name) == 0) {
  732.         yylval.Number = tp->value;
  733.         return tp->type;
  734.     }
  735.     }
  736.  
  737.     for (tp = TimezoneTable; tp->name; tp++)
  738.     if (strcmp(buff, tp->name) == 0) {
  739.         yylval.Number = tp->value;
  740.         return tp->type;
  741.     }
  742.  
  743.     if (strcmp(buff, "dst") == 0) 
  744.     return tDST;
  745.  
  746.     for (tp = UnitsTable; tp->name; tp++)
  747.     if (strcmp(buff, tp->name) == 0) {
  748.         yylval.Number = tp->value;
  749.         return tp->type;
  750.     }
  751.  
  752.     /* Strip off any plural and try the units table again. */
  753.     i = strlen(buff) - 1;
  754.     if (buff[i] == 's') {
  755.     buff[i] = '\0';
  756.     for (tp = UnitsTable; tp->name; tp++)
  757.         if (strcmp(buff, tp->name) == 0) {
  758.         yylval.Number = tp->value;
  759.         return tp->type;
  760.         }
  761.     buff[i] = 's';        /* Put back for "this" in OtherTable. */
  762.     }
  763.  
  764.     for (tp = OtherTable; tp->name; tp++)
  765.     if (strcmp(buff, tp->name) == 0) {
  766.         yylval.Number = tp->value;
  767.         return tp->type;
  768.     }
  769.  
  770.     /* Military timezones. */
  771.     if (buff[1] == '\0' && isalpha(*buff)) {
  772.     for (tp = MilitaryTable; tp->name; tp++)
  773.         if (strcmp(buff, tp->name) == 0) {
  774.         yylval.Number = tp->value;
  775.         return tp->type;
  776.         }
  777.     }
  778.  
  779.     /* Drop out any periods and try the timezone table again. */
  780.     for (i = 0, p = q = buff; *q; q++)
  781.     if (*q != '.')
  782.         *p++ = *q;
  783.     else
  784.         i++;
  785.     *p = '\0';
  786.     if (i)
  787.     for (tp = TimezoneTable; tp->name; tp++)
  788.         if (strcmp(buff, tp->name) == 0) {
  789.         yylval.Number = tp->value;
  790.         return tp->type;
  791.         }
  792.  
  793.     return tID;
  794. }
  795.  
  796.  
  797. int
  798. yylex()
  799. {
  800.     register char    c;
  801.     register char    *p;
  802.     char        buff[20];
  803.     int            Count;
  804.     int            sign;
  805.  
  806.     for ( ; ; ) {
  807.     while (isspace(*yyInput))
  808.         yyInput++;
  809.  
  810.     if (isdigit(c = *yyInput) || c == '-' || c == '+') {
  811.         if (c == '-' || c == '+') {
  812.         sign = c == '-' ? -1 : 1;
  813.         if (!isdigit(*++yyInput))
  814.             /* skip the '-' sign */
  815.             continue;
  816.         }
  817.         else
  818.         sign = 0;
  819.         for (yylval.Number = 0; isdigit(c = *yyInput++); )
  820.         yylval.Number = 10 * yylval.Number + c - '0';
  821.         yyInput--;
  822.         if (sign < 0)
  823.         yylval.Number = -yylval.Number;
  824.         return sign ? tSNUMBER : tUNUMBER;
  825.     }
  826.     if (isalpha(c)) {
  827.         for (p = buff; isalpha(c = *yyInput++) || c == '.'; )
  828.         if (p < &buff[sizeof buff - 1])
  829.             *p++ = c;
  830.         *p = '\0';
  831.         yyInput--;
  832.         return LookupWord(buff);
  833.     }
  834.     if (c != '(')
  835.         return *yyInput++;
  836.     Count = 0;
  837.     do {
  838.         c = *yyInput++;
  839.         if (c == '\0')
  840.         return c;
  841.         if (c == '(')
  842.         Count++;
  843.         else if (c == ')')
  844.         Count--;
  845.     } while (Count > 0);
  846.     }
  847. }
  848.  
  849.  
  850. time_t
  851. get_date(p, now)
  852.     char        *p;
  853.     struct timeb    *now;
  854. {
  855.     struct tm        *tm;
  856.     struct timeb    ftz;
  857.     time_t        Start;
  858.     time_t        tod;
  859.  
  860.     yyInput = p;
  861.     if (now == NULL) {
  862.         now = &ftz;
  863. #if    !defined(HAVE_FTIME)
  864.     (void)time(&ftz.time);
  865.     /* Set the timezone global. */
  866.     tzset();
  867.     {
  868. #if sgi
  869.         ftz.timezone = (int) _timezone / 60;
  870. #else /* not sgi */
  871. #ifdef __386BSD__
  872.         ftz.timezone = 0;
  873. #else /* neither sgi nor 386BSD */
  874. #if defined (USG)
  875.         extern time_t timezone;
  876.  
  877.         ftz.timezone = (int) timezone / 60;
  878. #else /* neither sgi nor 386BSD nor USG */
  879.         struct timeval tv;
  880.         struct timezone tz;
  881.  
  882.         gettimeofday (&tv, &tz);
  883.         ftz.timezone = (int) tz.tz_minuteswest;
  884. #endif /* neither sgi nor 386BSD nor USG */
  885. #endif /* neither sgi nor 386BSD */
  886. #endif /* not sgi */
  887.     }
  888. #else /* HAVE_FTIME */
  889.     (void)ftime(&ftz);
  890. #endif /* HAVE_FTIME */
  891.     }
  892.  
  893.     tm = localtime(&now->time);
  894.     yyYear = tm->tm_year;
  895.     yyMonth = tm->tm_mon + 1;
  896.     yyDay = tm->tm_mday;
  897.     yyTimezone = now->timezone;
  898.     yyDSTmode = DSTmaybe;
  899.     yyHour = 0;
  900.     yyMinutes = 0;
  901.     yySeconds = 0;
  902.     yyMeridian = MER24;
  903.     yyRelSeconds = 0;
  904.     yyRelMonth = 0;
  905.     yyHaveDate = 0;
  906.     yyHaveDay = 0;
  907.     yyHaveRel = 0;
  908.     yyHaveTime = 0;
  909.     yyHaveZone = 0;
  910.  
  911.     if (yyparse()
  912.      || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
  913.     return -1;
  914.  
  915.     if (yyHaveDate || yyHaveTime || yyHaveDay) {
  916.     Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
  917.             yyMeridian, yyDSTmode);
  918.     if (Start < 0)
  919.         return -1;
  920.     }
  921.     else {
  922.     Start = now->time;
  923.     if (!yyHaveRel)
  924.         Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec;
  925.     }
  926.  
  927.     Start += yyRelSeconds;
  928.     Start += RelativeMonth(Start, yyRelMonth);
  929.  
  930.     if (yyHaveDay && !yyHaveDate) {
  931.     tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber);
  932.     Start += tod;
  933.     }
  934.  
  935.     /* Have to do *something* with a legitimate -1 so it's distinguishable
  936.      * from the error return value.  (Alternately could set errno on error.) */
  937.     return Start == -1 ? 0 : Start;
  938. }
  939.  
  940.  
  941. #if    defined(TEST)
  942.  
  943. /* ARGSUSED */
  944. main(ac, av)
  945.     int        ac;
  946.     char    *av[];
  947. {
  948.     char    buff[128];
  949.     time_t    d;
  950.  
  951.     (void)printf("Enter date, or blank line to exit.\n\t> ");
  952.     (void)fflush(stdout);
  953.     while (gets(buff) && buff[0]) {
  954.     d = get_date(buff, (struct timeb *)NULL);
  955.     if (d == -1)
  956.         (void)printf("Bad format - couldn't convert.\n");
  957.     else
  958.         (void)printf("%s", ctime(&d));
  959.     (void)printf("\t> ");
  960.     (void)fflush(stdout);
  961.     }
  962.     exit(0);
  963.     /* NOTREACHED */
  964. }
  965. #endif    /* defined(TEST) */
  966.